home *** CD-ROM | disk | FTP | other *** search
/ Windows 95 API Bible / Windows 95 API Bible 3 Disc Set.iso / Win32 API Bible Book 3 of 3.iso / chapte17 / mixer2.c < prev    next >
C/C++ Source or Header  |  1996-04-29  |  30KB  |  860 lines

  1.  
  2. #include <windows.h>
  3. #include <stdio.h>
  4. #include "mixer2.h"
  5.  
  6. #if defined (WIN32)
  7.     #define IS_WIN32 TRUE
  8. #else
  9.     #define IS_WIN32 FALSE
  10. #endif
  11.  
  12. #define IS_NT      IS_WIN32 && (BOOL)(GetVersion() < 0x80000000)
  13. #define IS_WIN32S  IS_WIN32 && (BOOL)(!(IS_NT) && (LOBYTE(LOWORD(GetVersion()))<4))
  14. #define IS_WIN95   (BOOL)(!(IS_NT) && !(IS_WIN32S)) && IS_WIN32
  15.  
  16. HINSTANCE hInst;   // current instance
  17.  
  18. LPCTSTR lpszAppName = "MyApp";
  19. LPCTSTR lpszTitle   = "mixerGetControlDetails()"; 
  20.  
  21. BOOL RegisterWin95( CONST WNDCLASS* lpwc );
  22.  
  23.  
  24. int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  25.                       LPTSTR lpCmdLine, int nCmdShow)
  26. {
  27.    MSG      msg;
  28.    HWND     hWnd; 
  29.    WNDCLASS wc;
  30.  
  31.    wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  32.    wc.lpfnWndProc   = (WNDPROC)WndProc;       
  33.    wc.cbClsExtra    = 0;                      
  34.    wc.cbWndExtra    = 0;                      
  35.    wc.hInstance     = hInstance;              
  36.    wc.hIcon         = LoadIcon (hInstance, lpszAppName); 
  37.    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  38.    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  39.    wc.lpszMenuName  = lpszAppName;              
  40.    wc.lpszClassName = lpszAppName;              
  41.  
  42.    if ( IS_WIN95 )
  43.    {
  44.       if ( !RegisterWin95( &wc ) )
  45.          return( FALSE );
  46.    }
  47.    else if ( !RegisterClass( &wc ) )
  48.       return( FALSE );
  49.  
  50.    hInst = hInstance; 
  51.  
  52.    hWnd = CreateWindow( lpszAppName, 
  53.                         lpszTitle,    
  54.                         WS_OVERLAPPEDWINDOW, 
  55.                         CW_USEDEFAULT, 0, 
  56.                         CW_USEDEFAULT, 0,  
  57.                         NULL,              
  58.                         NULL,              
  59.                         hInstance,         
  60.                         NULL               
  61.                       );
  62.  
  63.    if ( !hWnd ) 
  64.       return( FALSE );
  65.  
  66.    ShowWindow( hWnd, nCmdShow ); 
  67.    UpdateWindow( hWnd );         
  68.  
  69.    while( GetMessage( &msg, NULL, 0, 0) )   
  70.    {
  71.       TranslateMessage( &msg ); 
  72.       DispatchMessage( &msg );  
  73.    }
  74.  
  75.    return( msg.wParam ); 
  76. }
  77.  
  78.  
  79. BOOL RegisterWin95( CONST WNDCLASS* lpwc )
  80. {
  81.     WNDCLASSEX wcex;
  82.  
  83.    wcex.style         = lpwc->style;
  84.    wcex.lpfnWndProc   = lpwc->lpfnWndProc;
  85.    wcex.cbClsExtra    = lpwc->cbClsExtra;
  86.    wcex.cbWndExtra    = lpwc->cbWndExtra;
  87.    wcex.hInstance     = lpwc->hInstance;
  88.    wcex.hIcon         = lpwc->hIcon;
  89.    wcex.hCursor       = lpwc->hCursor;
  90.    wcex.hbrBackground = lpwc->hbrBackground;
  91.    wcex.lpszMenuName  = lpwc->lpszMenuName;
  92.    wcex.lpszClassName = lpwc->lpszClassName;
  93.  
  94.    // Added elements for Windows 95.
  95.    //...............................
  96.    wcex.cbSize = sizeof(WNDCLASSEX);
  97.    wcex.hIconSm = LoadImage(wcex.hInstance, lpwc->lpszClassName, 
  98.                             IMAGE_ICON, 16, 16,
  99.                             LR_DEFAULTCOLOR );
  100.             
  101.    return RegisterClassEx( &wcex );
  102. }
  103.  
  104. #define MSG_LEN          1024
  105.  
  106.  
  107. char       msg[MSG_LEN+1];
  108.  
  109. MMRESULT   rc;
  110. UINT       nDevId      = 0;
  111. HMIXER     hmx         = NULL;
  112. HWND       hControlDlg = NULL;  // handle to the volume control dialog if open
  113.                                 // so that we can forward mixer messages.
  114.  
  115. VOID          AdjustMainVolume(HWND hWnd);
  116. VOID          LocateVolumeControl(HWND hWnd, DWORD dwLineId);
  117. BOOL CALLBACK DisplayControlDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  118.  
  119.  
  120. LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  121. {
  122.    switch( uMsg )
  123.    {
  124.       case WM_COMMAND :
  125.               switch( LOWORD( wParam ) )
  126.               {
  127.                  case IDM_TEST:
  128.                         {
  129.                            // check if there are any mixers installed
  130.                            //........................................
  131.  
  132.                            if (mixerGetNumDevs() == 0)
  133.                            {
  134.                                MessageBox(hWnd, "No audio mixer devices found.", 
  135.                                           NULL, MB_OK);
  136.                                DestroyWindow(hWnd);  // shut down. app is not of any use.
  137.                                break;
  138.                            }
  139.  
  140.                            // open first mixer device installed 
  141.                            // most systems only have one
  142.                            //..................................
  143.  
  144.                            rc = mixerOpen(&hmx, nDevId, (DWORD)hWnd, (DWORD)NULL,
  145.                                           CALLBACK_WINDOW);
  146.  
  147.                            if (rc != MMSYSERR_NOERROR)
  148.                            {
  149.                                MessageBox(hWnd, "Error opening mixer DevId = 0", 
  150.                                           NULL, MB_OK);
  151.                                mixerClose(hmx);
  152.                                DestroyWindow(hWnd);  // shut down
  153.                                break;
  154.                            }
  155.  
  156.                            // modify master volume control
  157.                            //.............................
  158.  
  159.                            AdjustMainVolume(hWnd);
  160.  
  161.                            // close mixer
  162.                            //............
  163.  
  164.                            mixerClose(hmx);
  165.                         }
  166.                         break;
  167.  
  168.                  case IDM_ABOUT :
  169.                         DialogBox( hInst, "AboutBox", hWnd, About );
  170.                         break;
  171.  
  172.                  case IDM_EXIT :
  173.                         DestroyWindow( hWnd );
  174.                         break;
  175.               }
  176.               break;
  177.  
  178.       // if the volume control dialog is active,
  179.       // forward the MM_MIXM_LINE_CHANGE and MM_MIXM_CONTROL_CHANGE
  180.       // messages to it.
  181.       //...........................................................
  182.  
  183.       case MM_MIXM_LINE_CHANGE:
  184.               {
  185.                  if (hControlDlg)
  186.                      SendMessage(hControlDlg, MM_MIXM_LINE_CHANGE, wParam, lParam);
  187.               }
  188.               break;
  189.  
  190.       case MM_MIXM_CONTROL_CHANGE:
  191.               {
  192.                  if (hControlDlg)
  193.                      SendMessage(hControlDlg, MM_MIXM_CONTROL_CHANGE, wParam, lParam);
  194.               }
  195.               break;
  196.  
  197.  
  198.       case WM_DESTROY :
  199.               PostQuitMessage(0);
  200.               break;
  201.  
  202.       default :
  203.             return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
  204.    }
  205.  
  206.    return( 0L );               
  207. }
  208.  
  209.  
  210. VOID AdjustMainVolume(HWND hWnd)
  211. {
  212.    UINT      uDest;
  213.    MIXERCAPS mxcaps;
  214.    MIXERLINE mxl;
  215.  
  216.    // search for main line output speakers
  217.    //.....................................
  218.  
  219.    mxcaps.cDestinations = 0;
  220.  
  221.    mixerGetDevCaps(nDevId, &mxcaps, sizeof(MIXERCAPS));
  222.    
  223.    for (uDest = 0; uDest < mxcaps.cDestinations; uDest++)
  224.    {
  225.       mxl.cbStruct      = sizeof(mxl);
  226.       mxl.dwDestination = uDest;
  227.  
  228.       // get line info
  229.       //..............
  230.  
  231.       rc = mixerGetLineInfo((HMIXEROBJ)hmx, &mxl, MIXER_GETLINEINFOF_DESTINATION);
  232.    
  233.       if (rc != MMSYSERR_NOERROR)
  234.       {
  235.           sprintf(msg, "mixerGetLineInfo(dst=%u) failed.  rc=%u!",
  236.                     uDest, rc); 
  237.           MessageBox(hWnd, msg, NULL, MB_OK);
  238.           continue;
  239.       }
  240.  
  241.       if (mxl.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS)
  242.       {
  243.           //MessageBox(hWnd, "Found it...", NULL, MB_OK);
  244.           LocateVolumeControl(hWnd, mxl.dwLineID);
  245.           return;
  246.       }
  247.    }
  248.  
  249.    MessageBox(hWnd, "Error, 'main line output speakers'"
  250.                     " component not found!", NULL, MB_OK);
  251. }
  252.  
  253.  
  254. VOID LocateVolumeControl(HWND hWnd, DWORD dwLineID)
  255. {
  256.     MMRESULT            rc;
  257.     MIXERLINE           mxl;
  258.     MIXERLINECONTROLS   mxlc;
  259.     PMIXERCONTROL       paMixerControls; // pamxctrl;
  260.     MIXERDLGDATA        mdd;             // used to pass data to DisplayControlDlg
  261.  
  262.  
  263.     mxl.cbStruct = sizeof(MIXERLINE);
  264.     mxl.dwLineID = dwLineID;
  265.  
  266.     rc = mixerGetLineInfo((HMIXEROBJ)hmx, &mxl, MIXER_GETLINEINFOF_LINEID);
  267.  
  268.     if (rc != MMSYSERR_NOERROR)
  269.     {
  270.         sprintf(msg,"mixerGetLineInfo(lineid=%.08lXh) failed.  rc=%u!",
  271.                 dwLineID, rc); 
  272.         MessageBox(hWnd, msg, NULL, MB_OK);
  273.         return;
  274.     }
  275.  
  276.     if (mxl.cControls == 0)
  277.     {
  278.         MessageBox(hWnd, "There are no controls associated with the selected line.",
  279.                    NULL, MB_OK);
  280.         return;
  281.     }
  282.  
  283.     // allocate memory for array of PMIXERCONTROL's
  284.     //.............................................
  285.  
  286.     paMixerControls = (PMIXERCONTROL)HeapAlloc(GetProcessHeap(), 
  287.                                                HEAP_ZERO_MEMORY, 
  288.                                                sizeof(MIXERCONTROL) * mxl.cControls);
  289.     
  290.     if (!paMixerControls)
  291.     {
  292.         MessageBox(hWnd, "Unable to allocate memory needed...", NULL, MB_OK);
  293.         return;
  294.     }
  295.  
  296.     // setup MIXERLINECONTROLS sttructure
  297.     //...................................
  298.  
  299.     mxlc.cbStruct       = sizeof(mxlc);
  300.     mxlc.dwLineID       = dwLineID;
  301.     mxlc.dwControlID    = 0;
  302.     mxlc.dwControlType  = 0;
  303.     mxlc.cControls      = mxl.cControls;
  304.     mxlc.cbmxctrl       = sizeof(MIXERCONTROL);
  305.     mxlc.pamxctrl       = paMixerControls;
  306.  
  307.     rc = mixerGetLineControls((HMIXEROBJ)hmx, &mxlc, MIXER_GETLINECONTROLSF_ALL);
  308.     
  309.     if (rc != MMSYSERR_NOERROR)
  310.     {
  311.         sprintf(msg, "mixerGetLineControls(ctrlid=%.08lXh) failed.  rc=%u!",
  312.                 dwLineID, rc); 
  313.         MessageBox(hWnd, msg, NULL, MB_OK);
  314.         // will exit after freeing allocated memory
  315.     }
  316.     else
  317.     {
  318.         UINT u;
  319.  
  320.         for (u = 0; u < mxlc.cControls; u++)
  321.         {
  322.             if (paMixerControls[u].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
  323.             {
  324.                 // verify that we have the right control
  325.                 //......................................
  326.  
  327.                 if ( !(paMixerControls[u].dwControlType & MIXERCONTROL_CONTROLTYPE_VOLUME) )
  328.                 {
  329.                     sprintf(msg, "Incorrect control type (dwControlType=%.08lXh).",
  330.                             paMixerControls[u].dwControlType); 
  331.                     MessageBox(hWnd, msg, NULL, MB_OK);
  332.                     return;
  333.                 }
  334.  
  335.                 // verify that control is active, otherwise, we can't
  336.                 // modify it, which is the whole point...
  337.                 //...................................................
  338.  
  339.                 if (paMixerControls[u].fdwControl & MIXERCONTROL_CONTROLF_DISABLED)
  340.                 {
  341.                     sprintf(msg, "This control (ctrlid=%.08lXh) is disabled.",
  342.                             paMixerControls[u].dwControlID); 
  343.                     MessageBox(hWnd, msg, NULL, MB_OK);
  344.                     return;
  345.                 }
  346.  
  347.                 // okay, now it's time to popup the control dialog
  348.                 // this stuff needs to be sent to the dialog
  349.                 //................................................
  350.  
  351.                 mdd.pmxl       = &mxl;
  352.                 mdd.pmxctrl    = &paMixerControls[u];
  353.  
  354.                 DialogBoxParam(hInst,
  355.                                "DisplayControlDlg",
  356.                                hWnd,
  357.                                DisplayControlDlg,
  358.                                (LPARAM)(LPVOID)&mdd);
  359.  
  360.                 // free array of mixer controls
  361.                 //.............................
  362.  
  363.                 HeapFree(GetProcessHeap(), 0, paMixerControls);
  364.                 return;
  365.             }
  366.             
  367.         }
  368.  
  369.         MessageBox(hWnd, "Unable to find volume control...", NULL, MB_OK);
  370.         return;
  371.     }
  372.  
  373.     HeapFree(GetProcessHeap(), 0, paMixerControls);
  374. }
  375.  
  376.  
  377. BOOL CALLBACK DisplayControlDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  378. {
  379.    static LPMIXERDLGDATA                pmdd     = NULL;
  380.    static LPMIXERLINE                   pmxl     = NULL;
  381.    static LPMIXERCONTROL                pmxctrl  = NULL;
  382.    static MIXERCONTROLDETAILS_UNSIGNED* pmxcdu   = NULL;
  383.    static int                           nRange   = 0;
  384.    static int                           nPageInc = 0;
  385.  
  386.    UINT                                 nChannels;
  387.    UINT                                 nMultipleItems;
  388.    
  389.  
  390.     switch (uMsg)
  391.     {
  392.         // init dialog
  393.         //.............
  394.         
  395.         case WM_INITDIALOG:
  396.                hControlDlg = hDlg;  // setup global handle so mixer messages
  397.                                     // can be forwarded from the main
  398.                                     // message loop
  399.  
  400.                pmdd = (LPMIXERDLGDATA)lParam;
  401.  
  402.                if (pmdd == NULL)
  403.                {
  404.                    EndDialog(hDlg, FALSE);
  405.                    return(TRUE);
  406.                }
  407.  
  408.                pmxl    = pmdd->pmxl;
  409.                pmxctrl = pmdd->pmxctrl;
  410.  
  411.                SetDlgItemText(hDlg, IDC_SHORTNAME_EC, pmxctrl->szShortName);
  412.                SetDlgItemText(hDlg, IDC_LONGNAME_EC,  pmxctrl->szName);
  413.  
  414.                sprintf(msg, "dwMinimum=%lu, dwMaximum=%lu",
  415.                        pmxctrl->Bounds.dwMinimum,
  416.                        pmxctrl->Bounds.dwMaximum);
  417.                SetDlgItemText(hDlg, IDC_BOUNDS_EC, msg);         
  418.                
  419.                sprintf(msg, "cSteps=%lu", pmxctrl->Metrics.cSteps); 
  420.                SetDlgItemText(hDlg, IDC_METRICS_EC, msg);
  421.  
  422.                nChannels = (UINT)pmxl->cChannels;
  423.             
  424.                if (pmxctrl->fdwControl & MIXERCONTROL_CONTROLF_UNIFORM)
  425.                    nChannels = 1;
  426.  
  427.                nMultipleItems = 1;
  428.             
  429.                if (pmxctrl->fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE)
  430.                    nMultipleItems = (UINT)pmxctrl->cMultipleItems;
  431.  
  432.                pmxcdu = (MIXERCONTROLDETAILS_UNSIGNED*)
  433.                         HeapAlloc(GetProcessHeap(),
  434.                                   HEAP_ZERO_MEMORY,
  435.                                   nChannels * nMultipleItems * 
  436.                                   sizeof(MIXERCONTROLDETAILS_UNSIGNED) 
  437.                                  );
  438.                                                         
  439.     
  440.                if (pmxcdu == NULL)
  441.                {
  442.                    MessageBox(hDlg, "Unable to allocate required memory...", NULL, MB_OK);
  443.                    EndDialog(hDlg, FALSE);
  444.                    return(TRUE);
  445.                }
  446.  
  447.                nRange = (int)min(32767, pmxctrl->Metrics.cSteps - 1);
  448.                nPageInc = nRange / 10;
  449.              
  450.                if (nPageInc == 0)
  451.                    nPageInc = 1;
  452.  
  453.                //  setup scoll bars
  454.                //..................
  455.             
  456.                {
  457.                   int  nSbWidth;
  458.                   HWND hSB;
  459.                   RECT rcM;
  460.                   RECT rcU;
  461.                   UINT u;
  462.                   UINT v;
  463.                   UINT uIndex;
  464.  
  465.                   nSbWidth = GetSystemMetrics(SM_CXVSCROLL);
  466.  
  467.                   GetWindowRect(GetDlgItem(hDlg, IDC_MULTICHANNEL_GRP), &rcM);
  468.  
  469.                   InflateRect(&rcM, -10, -20);
  470.                   ScreenToClient(hDlg, (LPPOINT)&rcM.left);
  471.                   ScreenToClient(hDlg, (LPPOINT)&rcM.right);
  472.  
  473.                   rcM.right = rcM.left + nSbWidth;
  474.  
  475.                   for (u = 0; u < nChannels; u++)
  476.                   {
  477.                      for (v = 0; v < nMultipleItems; v++)
  478.                      {
  479.                         uIndex = (u * nMultipleItems) + v;
  480.  
  481.                         hSB = CreateWindow("scrollbar", "", 
  482.                                            WS_VISIBLE | WS_CHILD | SBS_VERT | WS_TABSTOP,
  483.                                            rcM.left, rcM.top,
  484.                                            rcM.right - rcM.left,
  485.                                            rcM.bottom - rcM.top,
  486.                                            hDlg, (HMENU)(IDCB_MULTICHANNEL + uIndex),
  487.                                            hInst, NULL);
  488.  
  489.                         SetScrollRange(hSB, SB_CTL, 0, nRange, FALSE);
  490.  
  491.                         rcM.left  += nSbWidth + 4;
  492.                         rcM.right += nSbWidth + 4;
  493.                      }
  494.  
  495.                      // add more separation space between scroll bars
  496.                      //..............................................
  497.  
  498.                      rcM.left  += nSbWidth;
  499.                      rcM.right += nSbWidth;
  500.                   }
  501.  
  502.                    hSB = GetDlgItem(hDlg, IDC_UNIFORM_GRP);
  503.                    GetWindowRect(hSB, &rcU);
  504.  
  505.                    InflateRect(&rcU, -10, -20);
  506.                    ScreenToClient(hDlg, (LPPOINT)&rcU.left);
  507.                    ScreenToClient(hDlg, (LPPOINT)&rcU.right);
  508.  
  509.                    rcU.right = rcU.left + nSbWidth;
  510.  
  511.                    for (v = 0; v < nMultipleItems; v++)
  512.                    {
  513.                       hSB = CreateWindow("scrollbar", "", 
  514.                                          WS_VISIBLE | WS_CHILD | SBS_VERT | WS_TABSTOP,
  515.                                          rcU.left, rcU.top,
  516.                                          rcU.right - rcU.left,
  517.                                          rcU.bottom - rcU.top,
  518.                                          hDlg, (HMENU)(IDCB_UNIFORM + v),
  519.                                          hInst, NULL);
  520.  
  521.                       SetScrollRange(hSB, SB_CTL, 0, nRange, FALSE);
  522.  
  523.                       rcU.left  += nSbWidth + 4;
  524.                       rcU.right += nSbWidth + 4;
  525.                    }
  526.  
  527.  
  528.                    SendMessage(hDlg, MM_MIXM_LINE_CHANGE,
  529.                                (WPARAM)hmx, pmxl->dwLineID);
  530.  
  531.                    SendMessage(hDlg, MM_MIXM_CONTROL_CHANGE,
  532.                                (WPARAM)hmx, pmxctrl->dwControlID);
  533.                }
  534.  
  535.                return(TRUE);
  536.  
  537.         // mixer line change
  538.         //..................
  539.  
  540.         case MM_MIXM_LINE_CHANGE:
  541.                {
  542.                   DWORD      dwLineID;
  543.                   MIXERLINE  mxl;
  544.                   BOOL       bSource;
  545.                   BOOL       bActive;
  546.                   BOOL       bDisconnected;
  547.  
  548.                   dwLineID = (DWORD)lParam;
  549.  
  550.                   if (pmxl->dwLineID != dwLineID)
  551.                       return(TRUE);  // not our mixer line
  552.  
  553.                   // get current state of mixer line
  554.                   //................................
  555.  
  556.                   mxl.cbStruct      = sizeof(MIXERLINE);
  557.                   mxl.dwLineID      = dwLineID;
  558.  
  559.                   rc = mixerGetLineInfo((HMIXEROBJ)hmx, &mxl, MIXER_GETLINEINFOF_LINEID);
  560.  
  561.                   if (rc != MMSYSERR_NOERROR)
  562.                   {
  563.                       sprintf(msg, "mixerGetLineInfo(lineid=%.08lXh) failed.  rc=%u!",
  564.                               dwLineID, rc);
  565.                       MessageBox(hDlg, msg, NULL, MB_OK);
  566.                       return (FALSE);
  567.                   }
  568.  
  569.                   bSource       = (MIXERLINE_LINEF_SOURCE & mxl.fdwLine)       != 0;
  570.                   bActive       = (MIXERLINE_LINEF_ACTIVE & mxl.fdwLine)       != 0;
  571.                   bDisconnected = (MIXERLINE_LINEF_DISCONNECTED & mxl.fdwLine) != 0;
  572.  
  573.                   sprintf(msg, "(%s), '%s', %s, %s",
  574.                                bSource ? (LPSTR)"Src" : (LPSTR)"Dest",
  575.                                (LPSTR)mxl.szShortName,
  576.                                bActive ? (LPSTR)"Active" : (LPSTR)"Inactive",
  577.                                bDisconnected ? (LPSTR)"Disconnected" : (LPSTR)"Connected");
  578.  
  579.                   SetDlgItemText(hDlg, IDC_LINEINFO_EC, msg);
  580.                }
  581.                return (TRUE);
  582.  
  583.         // mixer control change
  584.         //.....................
  585.  
  586.         case MM_MIXM_CONTROL_CHANGE:
  587.                {
  588.                   HWND                hFocus;
  589.                   HWND                hSB;
  590.                   UINT                uIndex, u, v;
  591.                   int                 nValue;
  592.                   MIXERCONTROLDETAILS mxcd;
  593.  
  594.                   hFocus = GetFocus();
  595.                   
  596.                   if (hFocus == NULL)
  597.                   {
  598.                       hFocus = GetDlgItem(hDlg, IDCB_MULTICHANNEL);
  599.                   }
  600.                   else
  601.                   {
  602.                       if (GetDlgCtrlID(hFocus) < IDCB_MULTICHANNEL)
  603.                           hFocus = GetDlgItem(hDlg, IDCB_MULTICHANNEL);
  604.                   }
  605.  
  606.                   nChannels = (UINT)pmxl->cChannels;
  607.                   
  608.                   if (pmxctrl->fdwControl & MIXERCONTROL_CONTROLF_UNIFORM)
  609.                       nChannels = 1;
  610.  
  611.                   mxcd.cbStruct       = sizeof(MIXERCONTROLDETAILS);
  612.                   mxcd.dwControlID    = pmxctrl->dwControlID;
  613.                   mxcd.cChannels      = nChannels;
  614.                   mxcd.cMultipleItems = pmxctrl->cMultipleItems;
  615.                   mxcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  616.                   mxcd.paDetails      = pmxcdu;
  617.  
  618.                   rc = mixerGetControlDetails((HMIXEROBJ)hmx, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
  619.                   
  620.                   if (rc != MMSYSERR_NOERROR)
  621.                   {
  622.                       sprintf(msg, "mixerGetControlDetails(ctrlid=%.08lXh) failed.  rc=%u!",
  623.                                 pmxctrl->dwControlID, rc);
  624.                       MessageBox(hDlg, msg, NULL, MB_OK);
  625.                       return (FALSE);
  626.                   }
  627.  
  628.                   nMultipleItems = 1;
  629.                   
  630.                   if (pmxctrl->fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE)
  631.                       nMultipleItems = (UINT)pmxctrl->cMultipleItems;
  632.  
  633.  
  634.                   for (u = 0; u < nChannels; u++)
  635.                   {
  636.                       for (v = 0; v < nMultipleItems; v++)
  637.                       {
  638.                           uIndex = (u * nMultipleItems) + v;
  639.                           nValue = (int)MulDiv(pmxcdu[uIndex].dwValue, nRange, 0xFFFF);
  640.  
  641.                           hSB = GetDlgItem(hDlg, IDCB_MULTICHANNEL + uIndex);
  642.  
  643.                           if (hSB == hFocus)
  644.                           {
  645.                               sprintf(msg, "step=%d, dwValue=%lu",
  646.                                       nValue, pmxcdu[uIndex].dwValue);
  647.                               SetDlgItemText(hDlg, IDC_VALUE_EC, msg);
  648.                           }
  649.  
  650.                           if (GetScrollPos(hSB, SB_CTL) == (nRange - nValue) )
  651.                               continue;
  652.  
  653.                           //  Fader controls increase as the thumb is moved up
  654.                           //  contrary to normal operation or a ScrollBar, so
  655.                           //  the action will be reversed
  656.                           //..................................................
  657.  
  658.                           SetScrollPos(hSB, SB_CTL, nRange - nValue, TRUE);
  659.                       }
  660.                   }
  661.  
  662.                   // okay, now lets do the whole thing over again 
  663.                   // for the uniform controls
  664.                   //.............................................
  665.  
  666.                   mxcd.cbStruct       = sizeof(MIXERCONTROLDETAILS);
  667.                   mxcd.dwControlID    = pmxctrl->dwControlID;
  668.                   mxcd.cChannels      = 1;
  669.                   mxcd.cMultipleItems = pmxctrl->cMultipleItems;
  670.                   mxcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  671.                   mxcd.paDetails      = pmxcdu;
  672.  
  673.                   rc = mixerGetControlDetails((HMIXEROBJ)hmx, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
  674.  
  675.                   if (rc != MMSYSERR_NOERROR)
  676.                   {
  677.                       sprintf(msg, "mixerGetControlDetails(ctrlid=%.08lXh) failed.  rc=%u!",
  678.                               pmxctrl->dwControlID, rc);
  679.                       MessageBox(hDlg, msg, NULL, MB_OK);
  680.                       return (FALSE);
  681.                   }
  682.  
  683.  
  684.                   for (v = 0; v < nMultipleItems; v++)
  685.                   {
  686.                       nValue = (int)MulDiv(pmxcdu[v].dwValue, nRange, 0xFFFF);
  687.  
  688.                       hSB = GetDlgItem(hDlg, IDCB_UNIFORM + v);
  689.                       
  690.                       if (hSB == hFocus)
  691.                       {
  692.                           sprintf(msg, "step=%d, dwValue=%lu",
  693.                                   nValue, pmxcdu[0].dwValue);
  694.                           SetDlgItemText(hDlg, IDC_VALUE_EC, msg);
  695.                       }
  696.  
  697.                       if (GetScrollPos(hSB, SB_CTL) == (nRange - nValue) )
  698.                           continue;
  699.  
  700.                       //  Fader controls increase as the thumb is moved up
  701.                       //  contrary to normal operation or a ScrollBar, so
  702.                       //  the action will be reversed
  703.                       //..................................................
  704.  
  705.                       SetScrollPos(hSB, SB_CTL, nRange - nValue, TRUE);
  706.                   }
  707.                }
  708.                return (TRUE);
  709.  
  710.         // vertical scroll
  711.         //................
  712.  
  713.         case WM_VSCROLL:
  714.                {
  715.                   int                 nValue;
  716.                   UINT                uID;
  717.                   HWND                hSB;
  718.                   SHORT               nPos;
  719.                   MIXERCONTROLDETAILS mxcd;
  720.  
  721.                   hSB  = (HWND)lParam;
  722.                   nPos = (SHORT)HIWORD(wParam);
  723.                   uID  = GetDlgCtrlID(hSB);
  724.  
  725.                   if (uID < IDCB_UNIFORM)
  726.                   {
  727.                       nChannels = (UINT)pmxl->cChannels;
  728.                       uID -= IDCB_MULTICHANNEL;
  729.  
  730.                       if (pmxctrl->fdwControl & MIXERCONTROL_CONTROLF_UNIFORM)
  731.                           nChannels = 1;
  732.                   }
  733.                   else
  734.                   {
  735.                       nChannels = 1;
  736.                       uID -= IDCB_UNIFORM;
  737.                   }
  738.  
  739.                   nValue = GetScrollPos(hSB, SB_CTL);
  740.  
  741.                   switch ( LOWORD(wParam) )
  742.                   {
  743.                      case SB_PAGEUP:
  744.                            nValue -= nPageInc;
  745.                            nValue = (nValue < 1) ? 0 : (nValue - 1);
  746.                            break;
  747.                      
  748.                      case SB_PAGEDOWN:
  749.                            nValue = (int)min(nRange, (LONG)nValue + nPageInc);
  750.                            break;
  751.                      
  752.                      case SB_LINEUP:
  753.                            nValue = (nValue < 1) ? 0 : (nValue - 1);
  754.                            break;
  755.                      
  756.                      case SB_LINEDOWN:
  757.                            nValue = (int)min(nRange, (LONG)nValue + 1);
  758.                            break;
  759.                      
  760.                      case SB_TOP:
  761.                            nValue = 0;
  762.                            break;
  763.  
  764.                      case SB_BOTTOM:
  765.                            nValue = nRange;
  766.                            break;
  767.  
  768.                      case SB_THUMBPOSITION:
  769.                      case SB_THUMBTRACK:
  770.                            nValue = nPos;
  771.                            break;
  772.  
  773.                      default:
  774.                            return(FALSE);
  775.                   }
  776.  
  777.                   mxcd.cbStruct       = sizeof(MIXERCONTROLDETAILS);
  778.                   mxcd.dwControlID    = pmxctrl->dwControlID;
  779.                   mxcd.cChannels      = nChannels;
  780.                   mxcd.cMultipleItems = pmxctrl->cMultipleItems;
  781.                   mxcd.cbDetails      = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  782.                   mxcd.paDetails      = pmxcdu;
  783.  
  784.                   rc = mixerGetControlDetails((HMIXEROBJ)hmx, &mxcd, 0L);
  785.                   
  786.                   if (rc != MMSYSERR_NOERROR)
  787.                   {
  788.                       sprintf(msg, "mixerGetControlDetails(ctrlid=%.08lXh) failed.  rc=%u!",
  789.                                 pmxctrl->dwControlID, rc);
  790.                       MessageBox(hDlg, msg, NULL, MB_OK);
  791.                       return (FALSE);
  792.                   }
  793.  
  794.                   pmxcdu[uID].dwValue = (DWORD)MulDiv((nRange - nValue), 0xFFFF, nRange);
  795.  
  796.                   rc = mixerSetControlDetails((HMIXEROBJ)hmx, &mxcd, 0L);
  797.                   
  798.                   if (rc != MMSYSERR_NOERROR)
  799.                   {
  800.                       sprintf(msg, "mixerSetControlDetails(ctrlid=%.08lXh) failed.  rc=%u!",
  801.                                 pmxctrl->dwControlID, rc);
  802.                       MessageBox(hDlg, msg, NULL, MB_OK);
  803.                       return (FALSE);
  804.                   }
  805.                }
  806.                return (TRUE);
  807.  
  808.         // commands
  809.         //.........
  810.  
  811.         case WM_COMMAND:
  812.                switch ( LOWORD(wParam) )
  813.                {
  814.                   // close down volume control dialog
  815.                   //.................................
  816.  
  817.                   case WM_CLOSE:
  818.                   case IDOK:
  819.                   case IDCANCEL:
  820.                          {
  821.                             HeapFree(GetProcessHeap(), 0, pmxcdu);
  822.                             EndDialog(hDlg, TRUE);
  823.                             hControlDlg = NULL;
  824.                          }
  825.                          break;
  826.                }
  827.                break;
  828.  
  829.     }
  830.  
  831.     return (FALSE);
  832. }
  833.  
  834.  
  835. LRESULT CALLBACK About( HWND hDlg,           
  836.                         UINT message,        
  837.                         WPARAM wParam,       
  838.                         LPARAM lParam)
  839. {
  840.    switch (message) 
  841.    {
  842.        case WM_INITDIALOG: 
  843.                return (TRUE);
  844.  
  845.        case WM_COMMAND:                              
  846.                if (   LOWORD(wParam) == IDOK         
  847.                    || LOWORD(wParam) == IDCANCEL)    
  848.                {
  849.                        EndDialog(hDlg, TRUE);        
  850.                        return (TRUE);
  851.                }
  852.                break;
  853.    }
  854.  
  855.    return (FALSE); 
  856. }
  857.  
  858.  
  859.  
  860.